﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using Infrastructure.Library;

namespace PictureManager.Core.Provider
{
    public partial class XmlProvider : PictureProvider
    {
        /// <summary>
        /// Inserts a new <see cref="PictureItem"/> into the data store specified by the provider.
        /// </summary>
        /// <param name="item">
        /// The picture Item to insert.
        /// </param>
        public override void InsertPictureItem(PictureItem item)
        {
            var list = PictureItem.PictureList;
            list.Add(item);

            this.WritePictureFile(list);
        }
        /// <summary>
        /// Deletes a <see cref="PictureItem"/> from the data store specified by the provider.
        /// </summary>
        /// <param name="item">
        /// The <see cref="PictureItem"/> to delete.
        /// </param>
        public override void DeletePictureItem(PictureItem item)
        {
            var list = PictureItem.PictureList;
            list.Remove(item);
            this.WritePictureFile(list);
        }
        /// <summary>
        /// Updates an existing <see cref="PictureItem"/> in the data store specified by the provider.
        /// </summary>
        /// <param name="item">
        /// The <see cref="PictureItem"/> to update.
        /// </param>
        public override void UpdatePictureItem(PictureItem item)
        {
            var list = PictureItem.PictureList;
            list.Remove(item);
            list.Add(item);
            this.WritePictureFile(list);
        }
        /// <summary>
        /// Retrieves all picture items from the provider and returns them in a list.
        /// </summary>
        /// <returns>A list of <see cref="PictureItem"/>.</returns>
        public override List<PictureItem> GetPictures()
        {
            var list = new List<PictureItem>();
            var fileName = this.StorageFolder + typeof(PictureItem).Name + ".xml";
            if (!File.Exists(fileName))
            {
                return list;
            }
            try
            {
                var doc = new XmlDocument();
                doc.Load(fileName);

                var nodes = doc.SelectNodes("Picture/Item");
                if (nodes != null)
                {
                    foreach (XmlNode node in nodes)
                    {
                        PictureItem pic = new PictureItem();
                        pic.ID = node.Attributes["ID"] == null ? Guid.NewGuid().ToString() : node.Attributes["ID"].InnerText;
                        pic.ParentID = node.Attributes["ParentID"] == null ? Guid.NewGuid().ToString() : node.Attributes["ParentID"].InnerText;
                        pic.Name = node.Attributes["Name"] == null ? null : node.Attributes["Name"].InnerText;
                        pic.Desc = node.Attributes["Desc"] == null ? null : node.Attributes["Desc"].InnerText;
                        pic.IsNameBeFileName = node.Attributes["IsNameBeFileName"] == null ? false : Boolean.Parse(node.Attributes["IsNameBeFileName"].InnerText);
                        pic.Path = node.Attributes["Path"] == null ? null : node.Attributes["Path"].InnerText;
                        pic.RelativePath = node.Attributes["RelativePath"] == null ? null : node.Attributes["RelativePath"].InnerText;
                        GetBusinessBase<PictureItem, String>(pic, node);
                        if (node.ChildNodes.Count > 0)
                        {
                            foreach (XmlNode fileNode in node.ChildNodes[0].ChildNodes)
                            {
                                String path = fileNode.Attributes["Path"] == null ? null : fileNode.Attributes["Path"].InnerText;
                                if (path != null && !pic.FileNames.ContainsKey(path))
                                    pic.FileNames.Add(path, fileNode.Attributes["Name"] == null ? null : fileNode.Attributes["Name"].InnerText);
                            }
                        }
                        list.Add(pic);
                        pic.MarkOld();
                    }
                }
                list.Sort();
            }
            catch (Exception ex)
            {
                UtilLib.Util.Log(UtilLib.LogLevel.Error, ex);
            }
            return list;
        }
        /// <summary>
        /// Gets a <see cref="PictureItem"/> based on a id.
        /// </summary>
        /// <param name="id">
        /// The <see cref="PictureItem"/>'s id.
        /// </param>
        /// <returns>
        /// A matching <see cref="PictureItem"/>
        /// </returns>
        public override PictureItem GetPictureItem(String id)
        {
            var pic = PictureItem.PictureList.Find(p => p.ID == id) ?? new PictureItem();
            pic.MarkOld();
            return pic;
        }

        public override void SavePictureList()
        {
            this.WritePictureFile(PictureItem.PictureList);
        }

        #region Private Methods

        /// <summary>
        /// The write blog roll file.
        /// </summary>
        /// <param name="blogRollItems">
        /// The blog roll items.
        /// </param>
        private void WritePictureFile(List<PictureItem> list)
        {
            Util.SyncPictureDataToFolder(PictureItem.PictureList);
            var fileName = this.StorageFolder + typeof(PictureItem).Name + ".xml";
            if (!System.IO.Directory.Exists(this.StorageFolder))
                System.IO.Directory.CreateDirectory(this.StorageFolder);
            if (System.IO.File.Exists(fileName))
            {
                FileStream stream = System.IO.File.Create(fileName);
                stream.Close();
                stream.Dispose();
            }
            using (var writer = new XmlTextWriter(fileName, Encoding.UTF8))
            {
                writer.Formatting = Formatting.Indented;
                writer.Indentation = 4;
                writer.WriteStartDocument(true);
                writer.WriteStartElement("Picture");
                list.ForEach(pic =>
                     {
                         writer.WriteStartElement("Item");

                         writer.WriteAttributeString("ParentID", pic.ParentID.ToString());
                         writer.WriteAttributeString("ID", pic.ID.ToString());
                         writer.WriteAttributeString("Name", pic.Name);
                         writer.WriteAttributeString("Desc", pic.Desc);
                         writer.WriteAttributeString("IsNameBeFileName", pic.IsNameBeFileName.ToString());
                         writer.WriteAttributeString("Path", pic.Path);
                         writer.WriteAttributeString("RelativePath", pic.RelativePath);
                         WriteBusinessBase<PictureItem, String>(pic, writer);
                         if (pic.FileNames.Count > 0)
                         {
                             writer.WriteStartElement("picFiles");
                             pic.FileNames.ToList().ForEach(file =>
                                 {
                                     writer.WriteStartElement("Item");
                                     writer.WriteAttributeString("Name", file.Value);
                                     writer.WriteAttributeString("Path", file.Key);
                                     writer.WriteEndElement();
                                 });
                             writer.WriteEndElement();
                         }
                         writer.WriteEndElement();
                         pic.MarkOld();
                     });
                writer.WriteEndElement();
            }
        }

        private void GetBusinessBase<T, TKey>(T item, XmlNode node) where T : BusinessBase<T, TKey>, new()
        {
            DateTime dateCreated = DateTime.MinValue;
            if (node.Attributes["DateCreated"] == null || !DateTime.TryParse(node.Attributes["DateCreated"].InnerText, out dateCreated))
                item.DateCreated = DateTime.MinValue;
            else
                item.DateCreated = dateCreated;
            DateTime dateModified = DateTime.MinValue;
            if (node.Attributes["DateModified"] == null || !DateTime.TryParse(node.Attributes["DateModified"].InnerText, out dateModified))
                item.DateModified = DateTime.MinValue;
            else
                item.DateModified = dateModified;

        }

        private void WriteBusinessBase<T, TKey>(T item, XmlTextWriter writer) where T : BusinessBase<T, TKey>, new()
        {
            writer.WriteAttributeString("DateCreated", item.DateCreated.ToString());
            writer.WriteAttributeString("DateModified", item.DateModified.ToString());
        }
        #endregion
    }
}
